
#include "incs.h"

#include "ProcessManager.h"


void ProcessManager::InitPendingProcs()
{
	// If some processes have not been initialized yet, initialize them
	// and add them to the main proc list so that they can be updated.
	if(!mInitProcList.empty())
	{
		copy(mInitProcList.begin(), mInitProcList.end(), 
			std::back_inserter(mProcList));
		for( ProcessList::iterator it = mProcList.begin(); it != mProcList.end();
			++it)
		{
			Process * pr = it->get();
			if(!pr->IsInitialized())
				pr->OnInitialize();
			pr->mInitialized = true;
		}
		mInitProcList.clear();	
	}
}

void ProcessManager::Update( int delta )
{
	InitPendingProcs();

	ProcessList::iterator it = mProcList.begin(); 
	while( it != mProcList.end() )
	{
		Process::Ptr pProc = *it;
		Process * pr = pProc.get();
		++it;

		// If the process is active, update it.
		if(pr->IsActive())
			pr->OnUpdate(delta);

		// If the process has finished, remove it and add dependent processes.
		if(pr->IsFinished())
		{
			// Detach the finished process. Note: Takes linear time. Could be optimized.
			mProcList.remove(pProc);
			pProc->mAttached = false;

			// Insert the ones that depend just on finish.
			for(ProcessList::iterator fit = pr->mDepOnFinish.begin() ; 
				fit != pr->mDepOnFinish.end(); ++fit )
				Attach(*fit);

			// Insert the ones that depend on finish and on success.
			if(pr->IsSuccessful())
				for(ProcessList::iterator sit = pr->mDepOnSuccess.begin() ; 
					sit != pr->mDepOnSuccess.end(); ++sit )
					Attach(*sit);

			// Re-initialize so that the processes we have just added can be updated
			// just now.
			InitPendingProcs();
		}
	}
}

void ProcessManager::Update( int delta, int type )
{
	InitPendingProcs();

	ProcessList::iterator it = mProcList.begin(); 
	while( it != mProcList.end() )
	{
		Process::Ptr pProc = *it;
		Process * pr = pProc.get();
		++it;

		if(pr->IsActive() && pr->GetType() == type)
			pr->OnUpdate(delta);
		if(pr->IsFinished())
		{
			// Detach the finished process. Note: Takes linear time. Could be optimized.
			mProcList.remove(pProc);
			pProc->mAttached = false;

			// Insert the ones that depend just on finish.
			for(ProcessList::iterator fit = pr->mDepOnFinish.begin() ; 
				fit != pr->mDepOnFinish.end(); ++fit )
				Attach(*fit);

			// Insert the ones that depend on finish and on success.
			if(pr->IsSuccessful())
				for(ProcessList::iterator sit = pr->mDepOnSuccess.begin() ; 
					sit != pr->mDepOnSuccess.end(); ++sit )
					Attach(*sit);

			// Re-initialize so that the processes we have just added can be updated
			// just now.
			InitPendingProcs();
		}
	}
}

void ProcessManager::Attach( Process::Ptr proc )
{
	mInitProcList.push_back(proc);
	proc->mAttached = true;
}


ProcessList ProcessManager::GetProcessList()
{
	ProcessList lst = mProcList;
	copy(mInitProcList.begin(), mInitProcList.end(), std::back_inserter(lst));
	return lst;
}